Перейти к основному содержимому

Компилятор GCC. Первая программа на Linux

Что такое GCC

GCC (GNU Compiler Collection) — набор компиляторов, разработанный в рамках проекта GNU. Является стандартным компилятором в большинстве Linux-дистрибутивов.

Установка GCC

sudo apt update
sudo apt install build-essential

Пакет build-essential включает: gcc, g++, make, libc-dev

Проверка установки:

gcc --version
which gcc

Первая программа

hello.c
#include <stdio.h>
#include <unistd.h>
#include <sys/utsname.h>

int main(void) {
printf("Hello, Linux!\n");

// Информация о компиляторе
printf("GCC version: %d.%d.%d\n",
__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__);

// Информация о системе
struct utsname system_info;
if (uname(&system_info) == 0) {
printf("System: %s %s\n",
system_info.sysname, system_info.release);
}

return 0;
}

Компиляция и запуск

Базовая компиляция

gcc hello.c -o hello
./hello

Этапы компиляции

# 1. Препроцессинг
gcc -E hello.c -o hello.i

# 2. Компиляция в ассемблер
gcc -S hello.c -o hello.s

# 3. Ассемблирование
gcc -c hello.c -o hello.o

# 4. Линковка
gcc hello.o -o hello
Совет

Используйте флаг -save-temps чтобы сохранить все промежуточные файлы:

gcc -save-temps hello.c -o hello

Основные флаги GCC

ФлагОписаниеПример
-oИмя выходного файлаgcc hello.c -o program
-WallОсновные предупрежденияgcc -Wall hello.c
-WextraДополнительные предупрежденияgcc -Wextra hello.c
-WerrorПредупреждения как ошибкиgcc -Werror hello.c
-gОтладочная информацияgcc -g hello.c
-O0Без оптимизации (по умолчанию)gcc -O0 hello.c
-O2Оптимизация уровня 2gcc -O2 hello.c
-O3Максимальная оптимизацияgcc -O3 hello.c
-std=c11Стандарт C11gcc -std=c11 hello.c
-pedanticСтрогое соответствие стандартуgcc -pedantic hello.c

Makefile для проекта

Makefile
CC = gcc
CFLAGS = -Wall -Wextra -std=c11
TARGET = program
SOURCES = main.c utils.c
OBJECTS = $(SOURCES:.c=.o)

# Основная цель
$(TARGET): $(OBJECTS)
$(CC) $(OBJECTS) -o $(TARGET)

# Правило для .o файлов
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@

# Отладочная версия
debug: CFLAGS += -g -O0 -DDEBUG
debug: clean $(TARGET)

# Релизная версия
release: CFLAGS += -O2 -DNDEBUG
release: clean $(TARGET)

# Запуск программы
run: $(TARGET)
./$(TARGET)

# Очистка
clean:
rm -f $(OBJECTS) $(TARGET)

# Полная очистка
distclean: clean
rm -f *.i *.s

.PHONY: clean distclean run debug release

Использование:

# Обычная сборка
make

# Отладочная версия
make debug

# Релизная версия
make release

# Запуск
make run

# Очистка
make clean

Работа с библиотеками

Математическая библиотека

math_example.c
#include <stdio.h>
#include <math.h>

int main(void) {
double x = 2.0;

printf("sqrt(%.1f) = %.4f\n", x, sqrt(x));
printf("sin(%.1f) = %.4f\n", x, sin(x));
printf("log(%.1f) = %.4f\n", x, log(x));

return 0;
}

Компиляция с библиотекой:

gcc math_example.c -o math_example -lm

Создание статической библиотеки

mylib.c
#include "mylib.h"

int add(int a, int b) {
return a + b;
}

int multiply(int a, int b) {
return a * b;
}
mylib.h
#ifndef MYLIB_H
#define MYLIB_H

int add(int a, int b);
int multiply(int a, int b);

#endif

Создание библиотеки:

# Компиляция в объектный файл
gcc -c mylib.c -o mylib.o

# Создание статической библиотеки
ar rcs libmylib.a mylib.o

# Использование библиотеки
gcc main.c -L. -lmylib -o program

Создание динамической библиотеки

# Компиляция с PIC (Position Independent Code)
gcc -fPIC -c mylib.c -o mylib.o

# Создание .so файла
gcc -shared mylib.o -o libmylib.so

# Использование
gcc main.c -L. -lmylib -o program

# Запуск (нужно указать путь к библиотеке)
LD_LIBRARY_PATH=. ./program

Отладка с GDB

Компиляция для отладки

gcc -g -O0 program.c -o program

Основные команды GDB

# Запуск отладчика
gdb ./program

# Команды в GDB:
break main # Точка останова на main
break file.c:10 # Точка останова на строке 10
run # Запуск программы
next # Следующая строка
step # Шаг с заходом в функции
print variable # Вывод значения переменной
continue # Продолжить выполнение
quit # Выход
Подсказка

Используйте gdb -tui program для текстового интерфейса с отображением кода

Профилирование с gprof

# Компиляция с профилированием
gcc -pg program.c -o program

# Запуск программы (создаст gmon.out)
./program

# Анализ результатов
gprof program gmon.out > analysis.txt

Проверка утечек памяти с Valgrind

memory_test.c
#include <stdio.h>
#include <stdlib.h>

int main(void) {
int *arr = malloc(10 * sizeof(int));

// Используем память
for (int i = 0; i < 10; i++) {
arr[i] = i * i;
}

// Забыли освободить - утечка!
// free(arr);

return 0;
}

Проверка:

gcc -g memory_test.c -o memory_test
valgrind --leak-check=full ./memory_test

Оптимизация кода

Флаги оптимизации

ФлагОписаниеКогда использовать
-O0Без оптимизацииОтладка
-O1Базовая оптимизацияБыстрая компиляция
-O2РекомендуемаяПродакшн
-O3АгрессивнаяКритичная производительность
-OsОптимизация размераВстраиваемые системы
-OfastМаксимальная скоростьНарушает стандарты

Пример влияния оптимизации

optimize_test.c
#include <stdio.h>
#include <time.h>

int main(void) {
clock_t start = clock();

long long sum = 0;
for (int i = 0; i < 1000000000; i++) {
sum += i;
}

clock_t end = clock();
double cpu_time = ((double)(end - start)) / CLOCKS_PER_SEC;

printf("Sum: %lld\n", sum);
printf("Time: %.3f seconds\n", cpu_time);

return 0;
}

Сравнение:

gcc -O0 optimize_test.c -o test_O0 && time ./test_O0
gcc -O2 optimize_test.c -o test_O2 && time ./test_O2
gcc -O3 optimize_test.c -o test_O3 && time ./test_O3

Кросс-компиляция

# Установка тулчейна для ARM
sudo apt install gcc-arm-linux-gnueabihf

# Компиляция для ARM
arm-linux-gnueabihf-gcc hello.c -o hello_arm

# Проверка типа файла
file hello_arm

Полезные команды и утилиты

КомандаОписание
gcc --versionВерсия компилятора
gcc -vПодробная информация о компиляции
gcc -dumpmachineЦелевая архитектура
gcc -dumpspecsСпецификации компилятора
ldd programЗависимости программы
nm programСимволы в программе
objdump -d programДизассемблер
size programРазмер секций
strip programУдаление символов
strace ./programТрассировка системных вызовов

Дополнительные материалы